﻿//  Copyright © Decebal Mihailescu 2013-2014
//  All rights reserved. This source code and binaries are distributed under 
//  Microsoft Public PatternLicense (Ms-PL)
//  The latest code is available at http://VSDesignPatterns.codeplex.com

//  Redistributions of source code must retain the above copyright notice, 
//  this list of conditions and the following disclaimer. 
//  Redistributions in binary form must reproduce the above copyright notice, 
//  this list of conditions and the following disclaimer in the documentation 
//  and/or other materials provided with the distribution. 

//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
//  REMAINS UNCHANGED.
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO;
using System.ComponentModel;
using System.Diagnostics;
using Microsoft.Win32;
using System.Net;
using System.Windows.Forms;
using System.Globalization;
using System.Security.AccessControl;
using System.Security.Principal;

namespace DesignPatternsWizard
{
    using Common;
#if !VS2015
    using Ionic.Zip;
#endif

    [Flags]
    public enum LocationsEnum : uint
    {
        None = 0,
        ContextProject = 1,
        Item = 2,
        Folder = 4,
        Tools = 8,
#if VS2015
        Code = 16,
#else
        Standard = 16,
#endif
        MenuProject = 32
    }

    [Flags]
    public enum ColumnsEnum : ulong
    {
        PatternAlias = 1,
        MinVSVersion = 2,
        CompilerSyntax = 4,
        ProgrammingStyle = 8,
        Category = 16,
        Culture = 32
    }

    public class ProjectInfo : IProjectInfo
    {
        readonly Stopwatch _stopWatch = new Stopwatch();
        public ProjectInfo(CodeLangEnum pt, string solutionFile)
        {
            _stopWatch.Start();
            this.CodeLang = pt;
            SolutionFileName = solutionFile;
        }

#region IServiceProvider Members

        virtual public object GetService(Type serviceType)
        {
            if (serviceType == typeof(IProjectInfo) || serviceType == typeof(IServiceProvider))
                return this;
            if (serviceType == typeof(IWizardWindow))
                return WizardWindow;
            object res = null;
            if (serviceType == typeof(IEnumerable<ILanguageProvider>))
            {
                IEnumerable<ILanguageProvider> prv = _langProvidersDict[this.CodeLang];
                return prv;
            }
            return res;

        }

#endregion
#region IProjectInfo Members

        public event CanUpdateVSProjectDelegate CanUpdateVSProject;
        public event UpdateVSProjectDelegate UpdateVSProject;
        public void OnUpdateVSProject(object sender, EventGeneration evgen)
        {

            if (UpdateVSProject == null || UpdateVSProject.GetInvocationList().Length < 1)
            {
                evgen.ErrorMsg = string.Format("No handler found for GeneratePattern event");
                evgen.Result = ResultEnum.UnknownError;
                return;
            }
            evgen.Result = ResultEnum.Success;

            UpdateVSProject(sender as IServiceProvider, evgen);


        }
        public void OnValidatePattern(object sender, EventValidaton evval)
        {

            evval.ErrorMsg = null;
            evval.Result = ResultEnum.Success;
            switch (evval.SelIndex)
            {
                case 2:

                    if (CanUpdateVSProject == null || CanUpdateVSProject.GetInvocationList().Length < 1)
                    {
                        evval.ErrorMsg = string.Format("No handler found for CanGeneratePattern event");
                        evval.Result = ResultEnum.UnknownError;
                        return;
                    }
                    CanUpdateVSProject(sender as IServiceProvider, evval);
                    break;
                default:
                    evval.Result = ResultEnum.Success;
                    evval.ErrorMsg = null;
                    break;
            }
        }
        public string ProjectName { get; set; }
        public string SolutionFileName { get; protected set; }
        public string FileName { get; set; }

        public CodeLangEnum CodeLang { get; set; }

        public IWizardWindow WizardWindow { get; internal set; }
        public TimeSpan LoadingTime
        {
            get
            {
                _stopWatch.Stop();
                return _stopWatch.Elapsed;
            }
        }

        public IEnumerable<ILanguageProvider> this[CodeLangEnum lang]
        {
            get
            {
                try
                {
                    IEnumerable<ILanguageProvider> langProviders = null;
                    _langProvidersDict.TryGetValue(this.CodeLang, out langProviders);
                    return langProviders;
                }
                catch (Exception ex)
                {
                    Logging.Instance.Log(1, "Exception thrown in ProjectInfo.this[CodeLangEnum lang] : {0}", ex.Message);
                    return null;
                }
            }

        }

        // if static should not store stale MEF data
        static readonly Dictionary<CodeLangEnum, IEnumerable<ILanguageProvider>> _langProvidersDict = new Dictionary<CodeLangEnum, IEnumerable<ILanguageProvider>>(3);//3 languages supported
        static internal void RefreshLangProviders()
        {
            _langProvidersDict.Clear();
        }
        public IEnumerable<ILanguageProvider> CreateSpecificLanguageProviders(Predicate<ILanguageProviderMetaData> filter)
        {
            try
            {
                //cash instances for language providers
                IEnumerable<ILanguageProvider> langProviders = this[CodeLang];
                //MEFController._parentWnd = this.WizardWindow as IWin32Window;
                MEFController.ProjectInfo = this;
                if (langProviders == null)
                {

                    if (!MEFController.Instance.GetLPInstatntiated(null).Any())
                        Logging.Instance.Log(2, "No Language Providers found in  ProjectInfo.CreateSpecificLanguageProviders");

                    langProviders = MEFController.Instance.GetLPInstatntiated(ilpmd =>
                        (((ilpmd.SupportedLangs | ilpmd.CompatibleLangs) & CodeLang) != default(CodeLangEnum))).Values;
                    if (langProviders != null && langProviders.Any())
                    {
                        _langProvidersDict.Add(CodeLang, langProviders);
                        //add compatible langs too if any
                        //langProviders = MEFController.Instance.GetLPInstatntiated(ilpmd => ((ilpmd.CompatibleLangs & CodeLang) != default(CodeLangEnum))).Values;
                        //if (langProviders != null && langProviders.Any())
                        //    _langProvidersDict.Add(CodeLang, langProviders);
                    }
                    else
                        return null;
                }
                return langProviders.Where(ilp =>
                {
                    ILanguageProviderMetaData ilpm = ilp.GetAsService<ILanguageProviderMetaData>();
                    return (ilpm == null) ? false : filter(ilpm);
                }).Where(x => x != null);
            }
            catch (Exception ex)
            {
                Logging.Instance.Log(1, "Exception thrown in  ProjectInfo.CreateSpecificLanguageProviders:{0}", ex);
                return null;
            }
        }
#endregion

        public Dictionary<string, string> ProjectProperties { get; set; }
    }

    static class NativeMethods
    {
        [DllImport("User32.Dll")]
        public static extern int GetDlgCtrlID(IntPtr hWndCtl);
    }

#region Windows Messages
    //see http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx   
    enum SystemCommands
    {
        SC_SIZE = 0xF000,
        SC_MOVE = 0xF010,
        SC_MINIMIZE = 0xF020,

        ///<summary>    
        /// Sent when form maximizes    
        ///</summary>    
        SC_MAXIMIZE = 0xF030,

        ///<summary>    /// Sent when form maximizes because of doubcle click on caption    
        /// JTE: Don't use this constant. As per the documentation, you    
        ///      must mask off the last 4 bits of wParam by AND'ing it    
        ///      with 0xFFF0. You can't assume the last 4 bits.     
        ///</summary>    
        SC_MAXIMIZE2 = 0xF032,
        SC_NEXTWINDOW = 0xF040,
        SC_PREVWINDOW = 0xF050,
        ///<summary>    
        /// Closes the form    
        ///</summary>    
        SC_CLOSE = 0xF060,
        SC_VSCROLL = 0xF070,
        SC_HSCROLL = 0xF080,
        SC_MOUSEMENU = 0xF090,
        SC_KEYMENU = 0xF100,
        SC_ARRANGE = 0xF110,
        ///<summary>    
        /// Sent when form is maximized from the taskbar    
        ///</summary>    
        SC_RESTORE = 0xF120,
        ///<summary>    
        /// Sent when form maximizes because of doubcle click on caption    
        /// JTE: Don't use this constant. As per the documentation, you    
        ///      must mask off the last 4 bits of wParam by AND'ing it    
        ///      with 0xFFF0. You can't assume the last 4 bits.     
        ///</summary>    
        SC_RESTORE2 = 0xF122,
        SC_TASKLIST = 0xF130,
        SC_SCREENSAVE = 0xF140,
        SC_HOTKEY = 0xF150,
        SC_DEFAULT = 0xF160,
        SC_MONITORPOWER = 0xF170,
        SC_CONTEXTHELP = 0xF180,
        SC_SEPARATOR = 0xF00F
    }
    enum Msg
    {
        WM_NULL = 0x0000,
        WM_CREATE = 0x0001,
        WM_DESTROY = 0x0002,
        WM_MOVE = 0x0003,
        WM_SIZE = 0x0005,
        WM_ACTIVATE = 0x0006,
        WM_SETFOCUS = 0x0007,
        WM_KILLFOCUS = 0x0008,
        WM_ENABLE = 0x000A,
        WM_SETREDRAW = 0x000B,
        WM_SETTEXT = 0x000C,
        WM_GETTEXT = 0x000D,
        WM_GETTEXTLENGTH = 0x000E,
        WM_PAINT = 0x000F,
        WM_CLOSE = 0x0010,
        WM_QUERYENDSESSION = 0x0011,
        WM_QUIT = 0x0012,
        WM_QUERYOPEN = 0x0013,
        WM_ERASEBKGND = 0x0014,
        WM_SYSCOLORCHANGE = 0x0015,
        WM_ENDSESSION = 0x0016,
        WM_SHOWWINDOW = 0x0018,
        WM_CTLCOLOR = 0x0019,
        WM_WININICHANGE = 0x001A,
        WM_SETTINGCHANGE = 0x001A,
        WM_DEVMODECHANGE = 0x001B,
        WM_ACTIVATEAPP = 0x001C,
        WM_FONTCHANGE = 0x001D,
        WM_TIMECHANGE = 0x001E,
        WM_CANCELMODE = 0x001F,
        WM_SETCURSOR = 0x0020,
        WM_MOUSEACTIVATE = 0x0021,
        WM_CHILDACTIVATE = 0x0022,
        WM_QUEUESYNC = 0x0023,
        WM_GETMINMAXINFO = 0x0024,
        WM_PAINTICON = 0x0026,
        WM_ICONERASEBKGND = 0x0027,
        WM_NEXTDLGCTL = 0x0028,
        WM_SPOOLERSTATUS = 0x002A,
        WM_DRAWITEM = 0x002B,
        WM_MEASUREITEM = 0x002C,
        WM_DELETEITEM = 0x002D,
        WM_VKEYTOITEM = 0x002E,
        WM_CHARTOITEM = 0x002F,
        WM_SETFONT = 0x0030,
        WM_GETFONT = 0x0031,
        WM_SETHOTKEY = 0x0032,
        WM_GETHOTKEY = 0x0033,
        WM_QUERYDRAGICON = 0x0037,
        WM_COMPAREITEM = 0x0039,
        WM_GETOBJECT = 0x003D,
        WM_COMPACTING = 0x0041,
        WM_COMMNOTIFY = 0x0044,
        WM_WINDOWPOSCHANGING = 0x0046,
        WM_WINDOWPOSCHANGED = 0x0047,
        WM_POWER = 0x0048,
        WM_COPYDATA = 0x004A,
        WM_CANCELJOURNAL = 0x004B,
        WM_NOTIFY = 0x004E,
        WM_INPUTLANGCHANGEREQUEST = 0x0050,
        WM_INPUTLANGCHANGE = 0x0051,
        WM_TCARD = 0x0052,
        WM_HELP = 0x0053,
        WM_USERCHANGED = 0x0054,
        WM_NOTIFYFORMAT = 0x0055,
        WM_CONTEXTMENU = 0x007B,
        WM_STYLECHANGING = 0x007C,
        WM_STYLECHANGED = 0x007D,
        WM_DISPLAYCHANGE = 0x007E,
        WM_GETICON = 0x007F,
        WM_SETICON = 0x0080,
        WM_NCCREATE = 0x0081,
        WM_NCDESTROY = 0x0082,
        WM_NCCALCSIZE = 0x0083,
        WM_NCHITTEST = 0x0084,
        WM_NCPAINT = 0x0085,
        WM_NCACTIVATE = 0x0086,
        WM_GETDLGCODE = 0x0087,
        WM_SYNCPAINT = 0x0088,
        WM_NCMOUSEMOVE = 0x00A0,
        WM_NCLBUTTONDOWN = 0x00A1,
        WM_NCLBUTTONUP = 0x00A2,
        WM_NCLBUTTONDBLCLK = 0x00A3,
        WM_NCRBUTTONDOWN = 0x00A4,
        WM_NCRBUTTONUP = 0x00A5,
        WM_NCRBUTTONDBLCLK = 0x00A6,
        WM_NCMBUTTONDOWN = 0x00A7,
        WM_NCMBUTTONUP = 0x00A8,
        WM_NCMBUTTONDBLCLK = 0x00A9,
        WM_NCXBUTTONDOWN = 0x00AB,
        WM_NCXBUTTONUP = 0x00AC,
        WM_NCXBUTTONDBLCLK = 0x00AD,
        WM_KEYDOWN = 0x0100,
        WM_KEYUP = 0x0101,
        WM_CHAR = 0x0102,
        WM_DEADCHAR = 0x0103,
        WM_SYSKEYDOWN = 0x0104,
        WM_SYSKEYUP = 0x0105,
        WM_SYSCHAR = 0x0106,
        WM_SYSDEADCHAR = 0x0107,
        WM_KEYLAST = 0x0108,
        WM_IME_STARTCOMPOSITION = 0x010D,
        WM_IME_ENDCOMPOSITION = 0x010E,
        WM_IME_COMPOSITION = 0x010F,
        WM_IME_KEYLAST = 0x010F,
        WM_INITDIALOG = 0x0110,
        WM_COMMAND = 0x0111,
        WM_SYSCOMMAND = 0x0112,
        WM_TIMER = 0x0113,
        WM_HSCROLL = 0x0114,
        WM_VSCROLL = 0x0115,
        WM_INITMENU = 0x0116,
        WM_INITMENUPOPUP = 0x0117,
        WM_MENUSELECT = 0x011F,
        WM_MENUCHAR = 0x0120,
        WM_ENTERIDLE = 0x0121,
        WM_MENURBUTTONUP = 0x0122,
        WM_MENUDRAG = 0x0123,
        WM_MENUGETOBJECT = 0x0124,
        WM_UNINITMENUPOPUP = 0x0125,
        WM_MENUCOMMAND = 0x0126,
        WM_CTLCOLORMSGBOX = 0x0132,
        WM_CTLCOLOREDIT = 0x0133,
        WM_CTLCOLORLISTBOX = 0x0134,
        WM_CTLCOLORBTN = 0x0135,
        WM_CTLCOLORDLG = 0x0136,
        WM_CTLCOLORSCROLLBAR = 0x0137,
        WM_CTLCOLORSTATIC = 0x0138,
        WM_MOUSEMOVE = 0x0200,
        WM_LBUTTONDOWN = 0x0201,
        WM_LBUTTONUP = 0x0202,
        WM_LBUTTONDBLCLK = 0x0203,
        WM_RBUTTONDOWN = 0x0204,
        WM_RBUTTONUP = 0x0205,
        WM_RBUTTONDBLCLK = 0x0206,
        WM_MBUTTONDOWN = 0x0207,
        WM_MBUTTONUP = 0x0208,
        WM_MBUTTONDBLCLK = 0x0209,
        WM_MOUSEWHEEL = 0x020A,
        WM_XBUTTONDOWN = 0x020B,
        WM_XBUTTONUP = 0x020C,
        WM_XBUTTONDBLCLK = 0x020D,
        WM_PARENTNOTIFY = 0x0210,
        WM_ENTERMENULOOP = 0x0211,
        WM_EXITMENULOOP = 0x0212,
        WM_NEXTMENU = 0x0213,
        WM_SIZING = 0x0214,
        WM_CAPTURECHANGED = 0x0215,
        WM_MOVING = 0x0216,
        WM_DEVICECHANGE = 0x0219,
        WM_MDICREATE = 0x0220,
        WM_MDIDESTROY = 0x0221,
        WM_MDIACTIVATE = 0x0222,
        WM_MDIRESTORE = 0x0223,
        WM_MDINEXT = 0x0224,
        WM_MDIMAXIMIZE = 0x0225,
        WM_MDITILE = 0x0226,
        WM_MDICASCADE = 0x0227,
        WM_MDIICONARRANGE = 0x0228,
        WM_MDIGETACTIVE = 0x0229,
        WM_MDISETMENU = 0x0230,
        WM_ENTERSIZEMOVE = 0x0231,
        WM_EXITSIZEMOVE = 0x0232,
        WM_DROPFILES = 0x0233,
        WM_MDIREFRESHMENU = 0x0234,
        WM_IME_SETCONTEXT = 0x0281,
        WM_IME_NOTIFY = 0x0282,
        WM_IME_CONTROL = 0x0283,
        WM_IME_COMPOSITIONFULL = 0x0284,
        WM_IME_SELECT = 0x0285,
        WM_IME_CHAR = 0x0286,
        WM_IME_REQUEST = 0x0288,
        WM_IME_KEYDOWN = 0x0290,
        WM_IME_KEYUP = 0x0291,
        WM_MOUSEHOVER = 0x02A1,
        WM_MOUSELEAVE = 0x02A3,
        WM_CUT = 0x0300,
        WM_COPY = 0x0301,
        WM_PASTE = 0x0302,
        WM_CLEAR = 0x0303,
        WM_UNDO = 0x0304,
        WM_RENDERFORMAT = 0x0305,
        WM_RENDERALLFORMATS = 0x0306,
        WM_DESTROYCLIPBOARD = 0x0307,
        WM_DRAWCLIPBOARD = 0x0308,
        WM_PAINTCLIPBOARD = 0x0309,
        WM_VSCROLLCLIPBOARD = 0x030A,
        WM_SIZECLIPBOARD = 0x030B,
        WM_ASKCBFORMATNAME = 0x030C,
        WM_CHANGECBCHAIN = 0x030D,
        WM_HSCROLLCLIPBOARD = 0x030E,
        WM_QUERYNEWPALETTE = 0x030F,
        WM_PALETTEISCHANGING = 0x0310,
        WM_PALETTECHANGED = 0x0311,
        WM_HOTKEY = 0x0312,
        WM_PRINT = 0x0317,
        WM_PRINTCLIENT = 0x0318,
        WM_THEME_CHANGED = 0x031A,
        WM_HANDHELDFIRST = 0x0358,
        WM_HANDHELDLAST = 0x035F,
        WM_AFXFIRST = 0x0360,
        WM_AFXLAST = 0x037F,
        WM_PENWINFIRST = 0x0380,
        WM_PENWINLAST = 0x038F,
        WM_APP = 0x8000,
        WM_USER = 0x0400,
        WM_REFLECT = WM_USER + 0x1c00
    }
    enum ControlsId : int
    {
        ButtonOk = 0x1,
        ButtonCancel = 0x2,
        ButtonHelp = 0x40E,//0x0000040e
        GroupFolder = 0x440,
        LabelFileType = 0x441,
        LabelFileName = 0x442,
        LabelLookIn = 0x443,
        DefaultView = 0x461,
        LeftToolBar = 0x4A0,
        ComboFileName = 0x47c,
        ComboFileType = 0x470,
        ComboFolder = 0x471,
        CheckBoxReadOnly = 0x410
    }
#endregion
    public class SortableBindingList<T> : BindingList<T>
    {
        private readonly Dictionary<Type, PropertyComparer<T>> comparers;
        private bool isSorted;
        private ListSortDirection listSortDirection;
        private PropertyDescriptor propertyDescriptor;
        public class PropertyComparer<U> : IComparer<U>
        {
            private readonly IComparer comparer;
            private PropertyDescriptor propertyDescriptor;
            private int reverse;

            public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
            {
                this.propertyDescriptor = property;
                Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
                this.comparer = (IComparer)comparerForPropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null);
                this.SetListSortDirection(direction);
            }

#region IComparer<T> Members

            public int Compare(U x, U y)
            {
                return this.reverse * this.comparer.Compare(this.propertyDescriptor.GetValue(x), this.propertyDescriptor.GetValue(y));
            }

#endregion

            private void SetPropertyDescriptor(PropertyDescriptor descriptor)
            {
                this.propertyDescriptor = descriptor;
            }

            private void SetListSortDirection(ListSortDirection direction)
            {
                this.reverse = direction == ListSortDirection.Ascending ? 1 : -1;
            }

            public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
            {
                this.SetPropertyDescriptor(descriptor);
                this.SetListSortDirection(direction);
            }
        }
        public SortableBindingList()
            : base(new List<T>())
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        public SortableBindingList(IEnumerable<T> enumeration)
            : base(new List<T>(enumeration))
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        protected override bool IsSortedCore
        {
            get { return this.isSorted; }
        }

        protected override PropertyDescriptor SortPropertyCore
        {
            get { return this.propertyDescriptor; }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get { return this.listSortDirection; }
        }

        protected override bool SupportsSearchingCore
        {
            get { return true; }
        }

        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
        {
            List<T> itemsList = (List<T>)this.Items;

            Type propertyType = property.PropertyType;
            PropertyComparer<T> comparer;
            if (!this.comparers.TryGetValue(propertyType, out comparer))
            {
                comparer = new PropertyComparer<T>(property, direction);
                this.comparers.Add(propertyType, comparer);
            }

            comparer.SetPropertyAndDirection(property, direction);
            itemsList.Sort(comparer);

            this.propertyDescriptor = property;
            this.listSortDirection = direction;
            this.isSorted = true;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        protected override void RemoveSortCore()
        {
            this.isSorted = false;
            this.propertyDescriptor = base.SortPropertyCore;
            this.listSortDirection = base.SortDirectionCore;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        protected override int FindCore(PropertyDescriptor property, object key)
        {
            int count = this.Count;
            for (int i = 0; i < count; ++i)
            {
                T element = this[i];
                if (property.GetValue(element).Equals(key))
                {
                    return i;
                }
            }

            return -1;
        }
    }


    public static class WizardUtils
    {
        /*
#if VS2008
        /// <summary>     
        /// The function determines whether the current operating system is a      
        /// 64-bit operating system.     
        /// </summary>     
        /// <returns>     
        /// The function returns true if the operating system is 64-bit;      
        /// otherwise, it returns false.     
        /// </returns>    
        public static bool IsWin64BitOS(this OperatingSystem os)
        {
            if (IntPtr.Size == 8)
                // 64-bit programs run only on Win64           
                return true;
            else// 32-bit programs run on both 32-bit and 64-bit Windows     
            {   // Detect whether the current process is a 32-bit process                
                // running on a 64-bit system.               
                return Process.GetCurrentProcess().Is64BitProc();
            }
        }


        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr GetModuleHandle(string moduleName);

        [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)]string procName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process);
#endif

        */

        //None = 0,
        //ContextProject = 1,
        //Item = 2,
        //Folder = 4,
        //Tools = 8,
        //Standard = 16,
        //MenuProject = 32
#if VS2008
        public const LocationsEnum DefaultLocations = LocationsEnum.ContextProject | LocationsEnum.Item | LocationsEnum.Folder | LocationsEnum.Tools | LocationsEnum.MenuProject;//(LocationsEnum)39;
# elif VS2015
        public const LocationsEnum DefaultLocations = LocationsEnum.ContextProject | LocationsEnum.Tools | LocationsEnum.MenuProject| LocationsEnum.Code;//(LocationsEnum)32;
#else
        public const LocationsEnum DefaultLocations = LocationsEnum.ContextProject | LocationsEnum.Tools | LocationsEnum.MenuProject;//(LocationsEnum)32;
#endif

#if VS2015
        /*      public static void PostInstallPackage()
              {
                  string crtFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                  //for including link to TemplateLibrary.zip see http://stackoverflow.com/questions/25788656/including-a-batch-file-with-vsix
                  string zipPath = Path.Combine(crtFolder, "TemplateLibrary.zip");
                  bool valExists = false;
                  RegistryKey regck = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
                  if (regck != null)
                  {
                      string templatesFolder = regck.GetValue("TemplateLibPath", null, RegistryValueOptions.None) as string;
                      valExists = !string.IsNullOrEmpty(templatesFolder) && Directory.Exists(templatesFolder);
                      regck.Close();
                  }
                  if (!valExists)
                  {
                          //using (RegistryKey reg = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, true))
                          //{

                          //    if (reg != null)
                          //    {
                          //        reg.SetValue("TemplateLibPath", Path.Combine(crtFolder, "TemplateLibrary"), RegistryValueKind.String);
                          //        Logging.Instance.Log(3, "Set reg value in Package initialization TemplateLibPath to  :" + Path.Combine(crtFolder, "TemplateLibrary"));
                          //        //MessageBox.Show("Set reg value in Package initialization TemplateLibPath to  :" + Path.Combine(crtFolder, "TemplateLibrary"), "Error in Package initialization");
                          //    }
                          //    else
                          //    {
                          //        Logging.Instance.Log(3, "Can't set value in Package initialization of TemplateLibPath in :" + Utils.AppHive);
                          //        // MessageBox.Show("Can't set value in Package initialization of TemplateLibPath in :" + Utils.AppHive, "Error in Package initialization");
                          //    }


                  }
                  if (!Directory.Exists(Path.Combine(crtFolder, "TemplateLibrary")) && File.Exists(zipPath))
                  {
                      dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
                      dynamic compressedFolderContents = shellApplication.NameSpace(zipPath).Items;
                      dynamic destinationFolder = shellApplication.NameSpace(crtFolder);
                      destinationFolder.CopyHere(compressedFolderContents);
                      Logging.Instance.Log(3, "Unpacked  TemplateLibrary in " + crtFolder);
                  }
              }*/
#endif
        public static LocationsEnum Locations
        {
            get
            {
                LocationsEnum loc = DefaultLocations;
                RegistryKey reg = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
                if (reg != null)
                {
                    object obj = reg.GetValue("Locations", loc, RegistryValueOptions.None);
                    loc = (LocationsEnum)System.Convert.ToUInt32(obj);
                    reg.Close();
                }
                return loc;
            }
            set
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey(Common.Utils.AppHive, RegistryKeyPermissionCheck.Default);
                if (reg != null)
                {
                    reg.SetValue("Locations", value, RegistryValueKind.DWord);
                    reg.Close();
                }

            }
        }
        public static int DaysToCheckOnline
        {
            get
            {
                RegistryKey reg = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
                int days = 15;
                if (reg != null)
                {
                    object obj = reg.GetValue("DaysToCheckOnline", 15, RegistryValueOptions.None);
                    days = System.Convert.ToInt32(obj);
                    if (days < 1)
                        days = 30;
                    reg.Close();
                }
                return days;
            }
            set
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey(Common.Utils.AppHive, RegistryKeyPermissionCheck.Default);
                if (reg != null)
                {
                    reg.SetValue("DaysToCheckOnline", value, RegistryValueKind.DWord);
                    reg.Close();
                }
            }
        }

        internal const ColumnsEnum DefaultColumns = ColumnsEnum.CompilerSyntax | ColumnsEnum.ProgrammingStyle | ColumnsEnum.Category;
        public static ColumnsEnum Columns
        {
            get
            {
                ColumnsEnum columns = WizardUtils.DefaultColumns;
                RegistryKey reg = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
                if (reg != null)
                {
                    object obj = reg.GetValue("Columns", columns, RegistryValueOptions.None);
                    columns = (ColumnsEnum)System.Convert.ToUInt64(obj);
                    reg.Close();
                }
                return columns;
            }
            set
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey(Common.Utils.AppHive, RegistryKeyPermissionCheck.Default);
                if (reg != null)
                {
                    reg.SetValue("Columns", value, RegistryValueKind.QWord);
                    reg.Close();
                }

            }
        }

        public static bool ShowFiltersPanel
        {
            get
            {
                bool show = false;
                RegistryKey reg = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
                if (reg != null)
                {
                    object obj = reg.GetValue("ShowFiltersPanel", 0, RegistryValueOptions.None);
                    show = ((uint)System.Convert.ToUInt32(obj) == 0) ? false : true;
                    reg.Close();
                }
                return show;
            }
            set
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey(Common.Utils.AppHive, RegistryKeyPermissionCheck.Default);
                if (reg != null)
                {
                    reg.SetValue("ShowFiltersPanel", value ? 1 : 0, RegistryValueKind.DWord);
                    reg.Close();
                }

            }
        }

        static public TEnum GetAllFlags<TEnum>() where TEnum : struct, IComparable, IFormattable, IConvertible
        {
            unchecked
            {
                if (!typeof(TEnum).IsEnum)
                    throw new InvalidOperationException("Can't get flags from non Enum");
                object val = null;
                switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TEnum))))
                {
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                        val = Enum.GetValues(typeof(TEnum))
                                    .Cast<Byte>()
                                    .Aggregate(default(Byte), (s, f) => (byte)(s | f));
                        break;
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                        val = Enum.GetValues(typeof(TEnum))
                                    .Cast<UInt16>()
                                    .Aggregate(default(UInt16), (s, f) => (UInt16)(s | f));
                        break;
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                        val = Enum.GetValues(typeof(TEnum))
                                    .Cast<UInt32>()
                                    .Aggregate(default(UInt32), (s, f) => (UInt32)(s | f));
                        break;
                    case TypeCode.Int64:
                    case TypeCode.UInt64:
                        val = Enum.GetValues(typeof(TEnum))
                                    .Cast<UInt64>()
                                    .Aggregate(default(UInt64), (s, f) => (UInt64)(s | f));
                        break;
                    default:
                        throw new InvalidOperationException("unhandled enum underlying type");

                }
                return (TEnum)Enum.ToObject(typeof(TEnum), val);
            }
        }

        //public static T GetAssemblyAttribute<T>(this System.Reflection.Assembly ass)
        //    where T : Attribute
        //{
        //    object[] attributes = ass.GetCustomAttributes(typeof(T), false);
        //    if (attributes == null || attributes.Length == 0)
        //        return null;
        //    return attributes.OfType<T>().SingleOrDefault();
        //}

        public static bool IsProviderInUse(ILanguageProviderMetaData ilpm)
        {
            ILangProviderRegistration r = Utils.LangProviderRegistration.GetLanguageProviderRegistration(ilpm.ProviderName);
            return (r == null) ? false : r.InUse;
        }

        //}
        //public static class RegistryUtilities
        //{
        /// <summary>
        /// Renames a subkey of the passed in registry key since 
        /// the Framework totally forgot to include such a handy feature.
        /// </summary>
        /// <param name="regKey">The RegistryKey that contains the subkey 
        /// you want to rename (must be writeable)</param>
        /// <param name="subKeyName">The name of the subkey that you want to rename
        /// </param>
        /// <param name="newSubKeyName">The new name of the RegistryKey</param>
        /// <returns>True if succeeds</returns>
        public static bool RenameSubKey(RegistryKey parentKey,
        string subKeyName, string newSubKeyName)
        {
            CopyKey(parentKey, subKeyName, newSubKeyName);
            parentKey.DeleteSubKeyTree(subKeyName);
            return true;
        }

        /// <summary>
        /// Copy a registry key. The parentKey must be writeable.
        /// </summary>
        /// <param name="parentKey"></param>
        /// <param name="keyNameToCopy"></param>
        /// <param name="newKeyName"></param>
        /// <returns></returns>
        public static bool CopyKey(RegistryKey parentKey,
        string keyNameToCopy, string newKeyName)
        {
            //Create new key
            using (RegistryKey destinationKey = parentKey.CreateSubKey(newKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                //Open the sourceKey we are copying from
                using (RegistryKey sourceKey = parentKey.OpenSubKey(keyNameToCopy))
                {
                    RecursiveCopyTo(sourceKey, destinationKey, ((_) => true), ((_) => true));
                }
            }
            return true;
        }

        public static bool RecursiveCopyTo(this RegistryKey sourceKey, RegistryKey destinationKey, Predicate<string> valueFilter, Predicate<string> keyFilter)
        {
            if (sourceKey == null || destinationKey == null || destinationKey == sourceKey)
                return false;
            bool bRes = true;
            try
            {
                //copy all the values
                foreach (string valueName in sourceKey.GetValueNames().Where(v => valueFilter(v)))
                {
                    //object objValue = sourceKey.GetValue(valueName);
                    //RegistryValueKind valKind = sourceKey.GetValueKind(valueName);
                    destinationKey.SetValue(valueName,
                        sourceKey.GetValue(valueName), sourceKey.GetValueKind(valueName));

                }

                //For Each subKey 
                //Create a new subKey in destinationKey 
                //Call self 
                foreach (string sourceSubKeyName in sourceKey.GetSubKeyNames().Where(k => keyFilter(k)))
                {
                    using (RegistryKey sourceSubKey = sourceKey.OpenSubKey(sourceSubKeyName, false))
                    {
                        using (RegistryKey destSubKey = destinationKey.CreateSubKey(sourceSubKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree))
                        {
                            bRes = RecursiveCopyTo(sourceSubKey, destSubKey, valueFilter, keyFilter);
                        }
                    }
                }
            }
            catch //(Exception ex)
            {

                bRes = false;
            }
            return bRes;
        }
        public static bool HasEscalatedPrivileges(WindowsBuiltInRole role)
        {
            using (WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent())
            {
                WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
                return windowsPrincipal.IsInRole(role);
            }

        }
    }
}
